﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Kooboo.Web.Mvc.Paging;
using Kooboo.Commerce.Contexts.Categories;
using Kooboo.Commerce.Contexts.ProductTypes;
using Kooboo.Commerce.Contexts.Brands;
using Kooboo.Commerce.Contexts.Taxes;
using Kooboo.Commerce.Contexts.ShopSettings;

namespace Kooboo.Web.Areas.Commerce.Controllers
{
    using Kooboo.Commerce;


    using Kooboo.IoC;
    using Kooboo.Web.Mvc;
    using Kooboo.Commerce.AddIn.Validators;
    using Kooboo.Commerce.Contexts.Products;
    using System.Threading;

    public class ProductController : ManagementController
    {
        #region Index and Search

        public ActionResult Index(int? page, int? pagesize)
        {
            var list = this.Actor
                .QueryProducts()
                .OrderByDescending(i => i.Id)
                .Select(i => new ProductModel
                {
                    Id = i.Id,
                    Name = i.Name,
                    BrandName = i.Brand.Name,
                    ProductTypeName = i.ProductType.Name,
                }).ToPagedList(page ?? 1, pagesize ?? Configuration.PageSize);

            BindSearchData(Enumerable.Empty<ICategory>());


            return View(list);
        }



        public ActionResult Search(int? page, string name, string sku,
                string categoryList, int? productTypeId, int? brandId, int? pagesize)
        {
            int[] CategoryList = null;
            if (!String.IsNullOrEmpty(categoryList))
            {
                var idlist = new List<Int32>();
                String[] array = categoryList.Split(',');
                foreach (var item in array)
                {
                    int id;
                    if (int.TryParse(item, out id))
                    {
                        idlist.Add(id);
                    }
                }
                CategoryList = idlist.ToArray();
            }

            var currentPageIndex = page.HasValue ? page.Value : 1;

            var list = this.Actor.QueryProducts();

            if (!String.IsNullOrWhiteSpace(name))
            {
                list = list.Where(it => it.Name.Contains(name));
            }

            if (!String.IsNullOrWhiteSpace(sku))
            {
                list = list.Where(i => i.SaleItems.Any(n => n.SKU.Contains(sku)));
            }


            if (CategoryList != null)
            {
                var categories = CategoryList.Select(i =>
                {
                    var category = ObjectContainer.CreateInstance<ICategory>();
                    category.Id = i;

                    return category;

                })
                .ToList();

                list.Where(i => i.Categories.Any(c => c.Id == i.Id));

                BindSearchData(categories);
            }
            else
            {
                BindSearchData(Enumerable.Empty<ICategory>());
            }

            if (productTypeId.HasValue)
            {
                list = list.Where(it => it.ProductType.Id == productTypeId.Value);
                var productType = ObjectContainer.CreateInstance<IProductType>();
                productType.Id = productTypeId.Value;
                ViewData["ProductType"] = productType;
            }

            if (brandId.HasValue)
            {
                list = list.Where(it => it.Brand.Id == brandId.Value);
                var brand = ObjectContainer.CreateInstance<IBrand>();
                brand.Id = brandId.Value;

                ViewData["Brand"] = brand;
            }

            var pageList = list
                .OrderByDescending(i => i.Id)
                .Select(i => new ProductModel
                {
                    Id = i.Id,
                    Name = i.Name,
                    BrandName = i.Brand.Name,
                    ProductTypeName = i.ProductType.Name,
                })
                .ToPagedList(page ?? 1, pagesize ?? Configuration.PageSize);

            return View("Index", pageList);
        }

        #endregion

        #region Create

        public ActionResult Create(int? producttypeid, int? brandid, int? categoryid)
        {

            var product = ObjectContainer.CreateInstance<IProduct>();

            //bind product type
            if (producttypeid.HasValue)
            {
                product.ProductType = this.Actor
                    .QueryProductTypes()
                    .Where(i => i.Id == producttypeid)
                    .FirstOrDefault();
            }

            //bind brand
            if (brandid.HasValue)
            {
                product.Brand = ObjectContainer.CreateInstance<IBrand>();
                product.Brand.Id = brandid.Value;
            }

            //bind categories
            if (categoryid.HasValue)
            {
                var list = new List<ICategory>();
                var category = ObjectContainer.CreateInstance<ICategory>();
                category.Id = categoryid.Value;
                list.Add(category);
                product.Categories = list.AsQueryable();
            }
            SetFieldValidators(product);
            SetVariationValidators(product);
            SetValidators(this.Url.Action<ProductController>(i => i.Create(producttypeid, brandid, categoryid)));
            SetActionLinks();
            SetSubmitAction(this.Url.Action<ProductController>(i => i.Create(producttypeid, brandid, categoryid)));
            SetSelector(product);
            SetShopSettings();
            SetItems(product);
            SetCultureName();

            return View(product);
        }



        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Create(IProduct product)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    this.Actor.Post(product, this.FindCategories());

                    return this.Redirect(this.Url.Action<ProductController>(i => i.Index(null, null)));
                }
                catch (Exception ex)
                {
                    return Json(new { Error = ex.Message + "\r\n" + ex.Source + "\r\n" + ex.StackTrace });
                }
            }

            return Json(new { Message = ModelState.GetErrorMessages() });
        }

        #endregion

        #region Edit

        public ActionResult Edit(int id)
        {
            var product = this.Actor
                .QueryProducts()
                .Where(i => i.Id == id)
                .FirstOrDefault();

            if (product == null)
            {
                return this.Redirect(this.Url.Action<ProductController>(i => i.Index(null, null)));
            }


            SetValidators(this.Url.Action<ProductController>(i => i.Edit(id)));
            SetVariationValidators(product);
            SetSubmitAction(this.Url.Action<ProductController>(i => i.Edit(id)));
            SetActionLinks();
            SetFieldValidators(product);
            SetShopSettings();
            SetSelector(product);
            SetItems(product);
            SetCultureName();

            return View(product);
        }



        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Edit(int id, IProduct product)
        {
            if (ModelState.IsValid)
            {
                try
                {
                    this.Actor.Put(product, this.FindCategories());

                    return this.Redirect(this.Url.Action<ProductController>(i => i.Index(null, null)));
                }
                catch (Exception ex)
                {
                    return Json(new { Error = ex.Message + "\\r\\n" + ex.Source + "\\r\\n" + ex.StackTrace });
                }
            }
            else
            {
                return Json(new { Message = ModelState.GetErrorMessages() });
            }
        }

        #endregion

        #region Helper

        void BindSearchData(IEnumerable<ICategory> categories)
        {
            ViewData["CategoryContainerID"] = "CategoryList";

            ViewData["proudct-search-action"] = this.Url.Action<ProductController>(i => i.Search(null, null, null, null, null, null, null));
            //ViewData["Categories"] = this.Actor.QueryCategories().Where(i => i.Parent == null).ToSelectableList(categories);
            //ViewData["Categories"] = this.Actor.QueryCategories().Where(i => i.Parent == null);
            //ViewData["Selected_Categories"] = categories;

            ViewData["ProductTypes"] = this.Actor.QueryProductTypes().Where(i => i.IsEnable).OrderBy(i => i.Name);

            var allCategories = this.Actor.QueryCategories().Where(i => i.Parent == null);
            ViewData["BindingCategories"] = CreateBindingCategories(allCategories, categories);
        }

        private void SetShopSettings()
        {
            var settings = this.Actor.GetShopSettings();

            ViewData["WeightUnit"] = settings.WeightUnit;
            ViewData["SizeUnit"] = settings.SizeUnit;
        }

        private void SetActionLinks()
        {
            ViewData["list_action"] = this.Url.Action<ProductController>(i => i.Index(null, null));
            ViewData["upload_action"] = this.Url.Action<ImageController>(i => i.Upload(Configuration.ProductImageFolder, false));
        }

        void SetSubmitAction(string url)
        {
            ViewData["product_action"] = url;
        }

        private void SetItems(IProduct product)
        {

            ViewData["SaleItems"] = product.SaleItems
                .Select(i => new
                {
                    i.Id,
                    ProductVariations = i.ProductVariations.Select(n => new
                    {
                        Id = n.Id,
                        VariationId = n.Variation.Id,
                        n.Value
                    }),
                    i.PurchasePrice,
                    i.RetailPrice,
                    i.SKU,
                    i.Stock,
                    DeliveryDays = i.DeliveryDays

                })
                .ToList()
                .SerializeToJson();

            if (product.ProductType == null)
            {
                ViewData["CustomFields"] = Enumerable.Empty<CustomFieldViewModel>();
            }
            else
            {
                ViewData["CustomFields"] = product
                    .ProductType
                    .CustomFields
                    .OrderBy(i => i.Sequence)
                    .Select((i, index) => new CustomFieldViewModel
                    {
                        CustomField = i,
                        ProductCustomField = product
                        .ProductCustomFields
                        .Where(m => m.CustomField.Id == i.Id)
                        .FirstOrDefault()
                    })
                    .AsEnumerable();
            }

            ViewData["ProductImages"] = product
                .ProductImages
                .Select(i => new ProductImageViewModel
                {
                    Id = i.Id,
                    CoverImage = i.CoverImage,
                    Name = i.Name,
                    ImageUrl = i.ThumnailUrl("product"),
                    OrignalImageUrl = i.DetailUrl("product")
                });
        }

        private void SetSelector(IProduct product)
        {
            ViewData["CategoryContainerID"] = "CategoryList";

            //ViewData["Categories"] = this.Actor.QueryCategories().Where(i => i.Parent == null).ToSelectableList(product.Categories);
            //ViewData["Categories"] = this.Actor.QueryCategories().Where(i => i.Parent == null);

            ViewData["Taxes"] = this.Actor.QueryTaxes().OrderBy(i => i.Name).ToSelectableList(product.Tax);
            ViewData["Brands"] = this.Actor.QueryBrands().OrderBy(i => i.Name).ToSelectableList(product.Brand);

            var allCategories = this.Actor.QueryCategories().Where(i => i.Parent == null);
            var selectedCategories = product.Categories;
            ViewData["BindingCategories"] = CreateBindingCategories(allCategories, selectedCategories);
        }

        private void SetValidators(string actionLink)
        {
            ViewData["Validators"] = ModelClientMetadataBuilder
                .BuildFor<IProduct>(actionLink)
                .ValidateFor(i => i.Name)
                .ValidateFor(i => i.Summary)
                .ToMetadata();

        }

        void SetFieldValidators(IProduct product)
        {
            var field_validators = ModelClientMetadataBuilder
                .BuildFor<IProductCustomField>("", "field_container");

            foreach (var field in product.ProductType.CustomFields)
            {
                field_validators.Validate(field.Name, field);
            }

            ViewData["Field_Validators"] = field_validators.ToMetadata();
        }

        void SetVariationValidators(IProduct product)
        {
            var validators = ModelClientMetadataBuilder
                .BuildFor<ISaleItem>("", "variation_container")
                .ValidateFor(i => i.DeliveryDays)
                .ValidateFor(i => i.PurchasePrice)
                .ValidateFor(i => i.RetailPrice)
                .ValidateFor(i => i.SKU)
                .ValidateFor(i => i.Stock);

            foreach (var variation in product.ProductType.Variations)
            {
                validators.Validate(variation.Name, variation);
            }

            ViewData["Variation_Validators"] = validators.ToMetadata();
        }

        private List<ICategory> FindCategories()
        {
            var value = this.ControllerContext.HttpContext.Request.Form["CategoryList"];
            List<ICategory> list = new List<ICategory>();

            if (string.IsNullOrWhiteSpace(value) == false)
            {
                var categories = value.Split(',');

                foreach (var i in categories)
                {
                    var item = ObjectContainer.CreateInstance<ICategory>();
                    item.Id = int.Parse(i);
                    list.Add(item);
                }

            } return list;
        }

        private void SetCultureName()
        {
            ViewData["Culture"] = Thread.CurrentThread.CurrentCulture.Name;
        }
        #endregion

        #region Delete

        [HttpPost]
        public ActionResult Delete(int id)
        {
            try
            {
                var product = ObjectContainer.CreateInstance<IProduct>();
                product.Id = id;

                this.Actor.Delete(product);
                return Json(true);

            }
            catch (Exception ex)
            {
                return Json(new { Error = ex.Message + "\\r\\n" + ex.Source + "\\r\\n" + ex.StackTrace });
            }

        }

        #endregion

        #region Product Reviews

        public ActionResult ReviewList(int? page, int id)
        {
            //var reviews = Services.Current.ProductReviews
            //        .FindAll()
            //        .Where(i => i.ProductId == id)
            //        .OrderByDescending(i => i.Id)
            //        .ToPagedList(page ?? 1, 2);

            //return View(reviews);
            return View();
        }

        #endregion

        [HttpPost]
        public ActionResult Hide(IProduct product)
        {
            // product.Hide();
            return this.RedirectToAction("Index");
        }

        [HttpPost]
        public ActionResult Show(IProduct product)
        {
            // product.Show();
            return this.RedirectToAction("Index");
        }

        [HttpPost]
        public ActionResult EnableBackOrder(IProduct product)
        {
            // product.EnableBackOrder();
            return this.RedirectToAction("Index");
        }

        [HttpPost]
        public ActionResult DisableBackOrder(IProduct product)
        {

            // product.DisableBackOrder();
            return this.RedirectToAction("Index");
        }

        /// <summary>
        /// combian categories and selected categories to a new object
        /// </summary>
        /// <param name="allCategories"></param>
        /// <param name="selectedCategories"></param>
        /// <returns></returns>
        private IEnumerable<BindingCategory> CreateBindingCategories(IEnumerable<ICategory> allCategories,
            IEnumerable<ICategory> selectedCategories)
        {
            if (allCategories != null && allCategories.Count() > 0)
            {
                if (selectedCategories == null || selectedCategories.Count() == 0)
                {
                    return allCategories.Select(c =>
                        new BindingCategory()
                        {
                            ID = c.Id,
                            Name = c.Name,
                            Selected = "",
                            Children = CreateBindingCategories(c.Children, selectedCategories)
                        });
                }
                else
                {
                    return allCategories.Select(c =>
                           new BindingCategory()
                           {
                               ID = c.Id,
                               Name = c.Name,
                               Selected = (selectedCategories.Where(sc => sc.Id == c.Id).Count() > 0 ? "checked" : ""),
                               Children = CreateBindingCategories(c.Children, selectedCategories)
                           });
                }
            }
            else
            {
                return Enumerable.Empty<BindingCategory>();
            }
        }
    }

    public class CustomFieldViewModel
    {
        public ICustomField CustomField
        {
            get;
            set;
        }

        public IProductCustomField ProductCustomField
        {
            get;
            set;
        }
    }

    public class ProductImageViewModel
    {

        public int Id
        {
            get;
            set;
        }

        public string Name
        {
            get;
            set;
        }


        public bool CoverImage
        {
            get;
            set;
        }

        /// <summary>
        /// thubmail image
        /// </summary>
        public string ImageUrl
        {
            get;
            set;
        }

        public String OrignalImageUrl { get; set; }

    }
}
